

package com.ruoyi.common.utils;


import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.core.CalcThreadManager;
import com.ruoyi.common.exception.ProcessStopException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteWatchdog;
import org.apache.commons.exec.PumpStreamHandler;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

import static cn.hutool.core.util.RuntimeUtil.destroy;


@Slf4j
public class ExecUtil {
	
	/**
     * 执行不需要返回结果的命令
     */
//     public static void execCmdWithoutResult(String command){
//    	 try {
//    		 //注意：第一个空格之后的所有参数都为参数
//    		 CommandLine cmdLine = new CommandLine(command);
//    		 //cmdLine.addArgument("");//添加命令，中间自动拼接空格
//    		 DefaultExecutor executor = new DefaultExecutor();
//    		 executor.setExitValue(1);
//    		 //设置60秒超时，执行超过60秒后会直接终止
//    		 //不设置超时
//    		 ExecuteWatchdog watchdog = new ExecuteWatchdog(-1);
//    		 executor.setWatchdog(watchdog);
//    		 DefaultExecuteResultHandler handler = new DefaultExecuteResultHandler();
//    		 executor.execute(cmdLine, handler);
//    		 //命令执行返回前一直阻塞
//    		 handler.waitFor();
//    	 } catch (Exception e) {
//    		 e.printStackTrace();
//    	 }
//     }

    /**
     * 带返回结果的命令执行
     * @param command（python执行命令）
     */
	public static String execCmdWithResult(String command) {
        try {
            log.info("pythonCmdWithResult-cmd: 【{}】", command);
            //String command = "ping 192.168.1.10";
            //接收正常结果流
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            //接收异常结果流
            ByteArrayOutputStream errorStream = new ByteArrayOutputStream();
            CommandLine commandline = CommandLine.parse(command);
            DefaultExecutor exec = new DefaultExecutor();
            exec.setExitValues(null);
            //不设置超时
            ExecuteWatchdog watchdog = new ExecuteWatchdog(-1);
            exec.setWatchdog(watchdog);
            PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream,errorStream);
            exec.setStreamHandler(streamHandler);
            exec.execute(commandline);
            //不同操作系统注意编码，否则结果乱码
            String out = outputStream.toString("UTF-8");
            String error = errorStream.toString("UTF-8");
            log.info("pythonCmdWithResult-res: 【{}】", out+error);
            return out+error;
        } catch (Exception e) {
            e.printStackTrace();
            return e.getMessage();
        }
    }

    public static String execPython(List<String> commandList, String sseId) throws ProcessStopException {
        commandList = commandList.stream().map(StringUtils::trim).filter(StrUtil::isNotBlank).collect(Collectors.toList());
        log.info("pythonCmd-all-cmd: 【{}】, sseId: {}", commandList.stream().collect(Collectors.joining(" ")), sseId);
        ProcessBuilder processBuilder = new ProcessBuilder(commandList);
        //将标准输入流和错误输入流合并，通过标准输入流读取信息
        processBuilder.redirectErrorStream(true);
        StringBuilder result = new StringBuilder();
        Process process = null;
        try {
            process = processBuilder.start();
            CalcThreadManager.addProcess(sseId,process);
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
            String packReadLine;
            while (null != (packReadLine = bufferedReader.readLine()) || process.isAlive()) {
                if (packReadLine == null) continue;
                System.out.println(Thread.currentThread().getName()+" 读取到: "+packReadLine);
                if (packReadLine.equals("null")){
                    continue;
                }
                if (packReadLine.contains("--")){
                    SseEmitterUtils.sendMessage(sseId,packReadLine.replaceAll("--","").replaceAll("%",""));
                }else {
                    result.append(packReadLine);
                }
            }
            bufferedReader.close();
            process.waitFor();

        } catch (Exception e) {
            if (e instanceof ProcessStopException) {
                log.info("线程终止");
                throw new ProcessStopException();
            }else {
                log.error("",e);
            }
        }
        log.info("pythonCmd-all-result, exitCode:【{}】, result: 【{}】", process.exitValue(), result);
        if (process.exitValue() >= 128) {
            //说明进程主动终止
            throw new ProcessStopException();
        }
        return result.toString();
    }

    public static String execPython(List<String> commandList, String sseId, String directory) throws ProcessStopException {
        commandList = commandList.stream().map(StringUtils::trim).filter(StrUtil::isNotBlank).collect(Collectors.toList());
        log.info("pythonCmd-all-cmd: 【{}】, sseId: {}, directory:{}", commandList.stream().collect(Collectors.joining(" ")), sseId, directory);
        ProcessBuilder processBuilder = new ProcessBuilder(commandList).directory(new File(directory));
        //将标准输入流和错误输入流合并，通过标准输入流读取信息
        processBuilder.redirectErrorStream(true);
        StringBuilder result = new StringBuilder();
        Process process = null;
        try {
            process = processBuilder.start();
            CalcThreadManager.addProcess(sseId,process);
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
            String packReadLine;
            while (null != (packReadLine = bufferedReader.readLine()) || process.isAlive()) {
                if (packReadLine == null) continue;
                System.out.println(Thread.currentThread().getName()+" 读取到: "+packReadLine);
                if (packReadLine.equals("null")){
                    continue;
                }
                if (packReadLine.contains("--")){
                    SseEmitterUtils.sendMessage(sseId,packReadLine.replaceAll("--","").replaceAll("%",""));
                }else {
                    result.append(packReadLine);
                }
            }
            bufferedReader.close();
            process.waitFor();

        } catch (Exception e) {
            if (e instanceof ProcessStopException) {
                log.info("线程终止");
                throw new ProcessStopException();
            }else {
                log.error("",e);
            }
        }

        log.info("pythonCmd-all-result: directory:{}, exitCode:【{}】, result: 【{}】",directory, process.exitValue(), result);
        if (process.exitValue() >= 128) {
            //说明进程主动终止
            throw new ProcessStopException();
        }
        return result.toString();
    }


    /**
     * TLE  不输出sse
     */
    public static String execTLENoSendSse(List<String> commandList, String sseId) throws ProcessStopException {
        log.info("execTLENoSendSse: 【{}】", commandList);
        StringBuilder result = new StringBuilder();
        ProcessBuilder processBuilder = new ProcessBuilder(commandList);
        Process process = null;
        try {
            process = processBuilder.start();
            if (StringUtils.isNotEmpty(sseId)) {
                CalcThreadManager.addProcess(sseId,process);
            }
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
            String packReadLine;
            while (null != (packReadLine = bufferedReader.readLine()) || process.isAlive()) {
                if (packReadLine == null) continue;
                result.append(packReadLine);
                result.append("\r\n");
            }
            bufferedReader.close();
            process.waitFor();
        } catch (Exception e) {
            if (e instanceof ProcessStopException) {
                log.info("线程终止");
                throw new ProcessStopException();
            }else {
                log.error("",e);
            }
        }
        log.info("execPython1-result: 【{}】,{}", process.exitValue(),result);
        if (process.exitValue() >= 128) {
            //说明进程主动终止
            throw new ProcessStopException();
        }
        return result.toString();
    }


    /**
     * 执行，但不输出sse 的 pyton日志
     * @param commandList
     * @param sseId
     * @return
     */
    public static String execPythonNoSendSse(List<String> commandList, String sseId) throws ProcessStopException {
        log.info("execPython1: 【{}】", commandList);
        StringBuilder result = new StringBuilder();
        ProcessBuilder processBuilder = new ProcessBuilder(commandList);
        Process process = null;
        try {
            process = processBuilder.start();
            if (StringUtils.isNotEmpty(sseId)) {
                CalcThreadManager.addProcess(sseId,process);
            }
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
            String packReadLine;
            while (null != (packReadLine = bufferedReader.readLine()) || process.isAlive()) {
                if (packReadLine == null) continue;
                if (!packReadLine.contains("--")){
                    result.append(packReadLine);
                }
            }
            bufferedReader.close();
            process.waitFor();
        } catch (Exception e) {
            if (e instanceof ProcessStopException) {
                log.info("线程终止");
                throw new ProcessStopException();
            }else {
                log.error("",e);
            }
        }
        log.info("execPython1-result: 【{}】,{}", process.exitValue(),result);
        if (process.exitValue() >= 128) {
            //说明进程主动终止
            throw new ProcessStopException();
        }
        return result.toString();
    }


    /**
     * 只是执行脚本,不带任何操作
     * @param commandList
     * @return
     */
    public static List<String> execPythonZw(List<String> commandList,String sseId) throws ProcessStopException {
        log.info("execPythonZw: 【{}】", commandList);
        ProcessBuilder processBuilder = new ProcessBuilder(commandList);
        processBuilder.redirectErrorStream(true);
        Process process = null;
        List<String> lines = new ArrayList<>();
        try {
            process = processBuilder.start();
            if (StringUtils.isNotEmpty(sseId)) {
                CalcThreadManager.addProcess(sseId,process);
            }


            String packReadLine = "";
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
            while (null != (packReadLine = bufferedReader.readLine()) || process.isAlive()) {
                if (packReadLine == null) continue;
                System.out.println(Thread.currentThread().getName()+" 读取到: "+packReadLine);
                if (packReadLine.equals("null")){
                    continue;
                }
                if (packReadLine.contains("--")){
                    SseEmitterUtils.sendMessage(sseId,packReadLine.replaceAll("--","").replaceAll("%",""));
                }else {
                    lines.add(packReadLine);
                }
            }
            process.waitFor();
        } catch (Exception e) {
            if (e instanceof ProcessStopException) {
                log.info("线程终止");
                throw new ProcessStopException();
            }else {
                log.error("",e);
            }
        }finally {
            destroy(process);
        }
        log.info("execPythonZw, exitCode:【{}】, result: 【{}】", process.exitValue(), lines);
        if (process.exitValue() >= 128) {
            //说明进程主动终止
            throw new ProcessStopException();
        }
        return lines;
    }

    /**
     * 需要传sseid
     * @param commandList
     * @param sseId
     * @return
     * @throws ProcessStopException
     */
    public static String execPythonNoTemplate(List<String> commandList, String sseId) throws ProcessStopException {
        log.info("pythonCmd-all-cmd: 【{}】, sseId: {}}", commandList.stream().collect(Collectors.joining(" ")), sseId);
        ProcessBuilder processBuilder = new ProcessBuilder(commandList);
        //将标准输入流和错误输入流合并，通过标准输入流读取信息
        processBuilder.redirectErrorStream(true);
        StringBuilder result = new StringBuilder();
        Process process = null;
        try {
            process = processBuilder.start();
            CalcThreadManager.addProcess(sseId,process);
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
            String packReadLine;
            while (null != (packReadLine = bufferedReader.readLine()) || process.isAlive()) {
                if (packReadLine == null) continue;
                //System.out.println(Thread.currentThread().getName()+" 读取到: "+packReadLine);
                if (packReadLine.equals("null")){
                    continue;
                }
                result.append(packReadLine);
                SseEmitterUtils.sendMessage(sseId, packReadLine);
            }
            bufferedReader.close();
            process.waitFor();
        } catch (Exception e) {
            if (e instanceof ProcessStopException) {
                log.info("线程终止");
                throw new ProcessStopException();
            }else {
                log.error("",e);
            }
        }
        log.info("pythonCmd-all-result, exitCode:【{}】, result: 【{}】", process.exitValue(), result);
        if (process.exitValue() >= 128) {
            //说明进程主动终止
            throw new ProcessStopException();
        }
        return result.toString();
    }


    /**
     * 需要传sseid
     * @param commandList
     * @param sseId
     * @param template
     * @return
     * @throws ProcessStopException
     */
    public static String execPythonWithMsgTemplate(List<String> commandList, String sseId , String template) throws ProcessStopException {
        commandList = commandList.stream().map(StringUtils::trim).filter(StrUtil::isNotBlank).collect(Collectors.toList());
        log.info("pythonCmd-all-cmd: 【{}】, sseId: {}, template:{}", commandList.stream().collect(Collectors.joining(" ")), sseId, template);
        ProcessBuilder processBuilder = new ProcessBuilder(commandList);
        //将标准输入流和错误输入流合并，通过标准输入流读取信息
        processBuilder.redirectErrorStream(true);
        StringBuilder result = new StringBuilder();
        Process process = null;
        try {
            process = processBuilder.start();
            CalcThreadManager.addProcess(sseId,process);
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
            String packReadLine;
            while (null != (packReadLine = bufferedReader.readLine()) || process.isAlive()) {
                if (packReadLine == null) continue;
                System.out.println(Thread.currentThread().getName()+" 读取到: "+packReadLine);
                if (packReadLine.equals("null")){
                    continue;
                }
                if (packReadLine.startsWith(">>>>>>")){
                    result.append(packReadLine);
                    continue;
                }
                SseEmitterUtils.sendMessage(sseId,template.replace("PLACEHOLDER", packReadLine));
            }
            bufferedReader.close();
            process.waitFor();
        } catch (Exception e) {
            if (e instanceof ProcessStopException) {
                log.info("线程终止");
                throw new ProcessStopException();
            }else {
                log.error("",e);
            }
        }
        log.info("pythonCmd-all-result, exitCode:【{}】, result: 【{}】", process.exitValue(), result);
        if (process.exitValue() >= 128) {
            //说明进程主动终止
            throw new ProcessStopException();
        }
        return result.toString();
    }
}
